New chapter about how to migrate from gnome-ui/bonobo-ui/etc. to
authorFederico Mena Quintero <federico@ximian.com>
Mon, 8 Dec 2003 22:28:27 +0000 (22:28 +0000)
committerFederico Mena Quintero <federico@src.gnome.org>
Mon, 8 Dec 2003 22:28:27 +0000 (22:28 +0000)
2003-12-08  Federico Mena Quintero  <federico@ximian.com>

* gtk/migrating-GtkAction.sgml: New chapter about how to migrate
from gnome-ui/bonobo-ui/etc. to GtkAction.

* gtk/gtk-docs.sgml: Integrated the above.

* gtk/Makefile.am (content_files): Added migrating-GtkAction.sgml.

docs/reference/ChangeLog
docs/reference/gtk/Makefile.am
docs/reference/gtk/gtk-docs.sgml
docs/reference/gtk/migrating-GtkAction.sgml [new file with mode: 0644]

index 6f9ff962873b2639fad7ee983293a86faa561ea1..6fa307e06829467f36007188b70d1614a2fae968 100644 (file)
@@ -1,3 +1,12 @@
+2003-12-08  Federico Mena Quintero  <federico@ximian.com>
+
+       * gtk/migrating-GtkAction.sgml: New chapter about how to migrate
+       from gnome-ui/bonobo-ui/etc. to GtkAction.
+
+       * gtk/gtk-docs.sgml: Integrated the above.
+
+       * gtk/Makefile.am (content_files): Added migrating-GtkAction.sgml.
+
 Sun Nov 23 20:59:57 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gtk/tree_widget.sgml: Add a missing comma.
index 206f117c3fa43b06ef3b97282633e506760af7c8..c5d3cf9603e8f594268c021a0316a6ac2a1f6a22 100644 (file)
@@ -85,6 +85,7 @@ content_files =                                       \
        changes-2.0.sgml                        \
        compiling.sgml                          \
        framebuffer.sgml                        \
+       migrating-GtkAction.sgml                \
        migrating-GtkFileChooser.sgml           \
        objects_grouped.sgml                    \
        question_index.sgml                     \
index 8cba90713a94c7dfa2e4b1df866fcbaffa0ce5f5..221a1c6a7999e5a1f571786fde09446939ae23ab 100644 (file)
 <!ENTITY gtk-Changes-1-2 SYSTEM "changes-1.2.sgml">
 <!ENTITY gtk-Changes-2-0 SYSTEM "changes-2.0.sgml">
 <!ENTITY gtk-migrating-GtkFileChooser SYSTEM "migrating-GtkFileChooser.sgml">
+<!ENTITY gtk-migrating-GtkAction SYSTEM "migrating-GtkAction.sgml">
 <!ENTITY version SYSTEM "version.xml">
 <!ENTITY gtk-query-immodules SYSTEM "gtk-query-immodules-2.0.xml">
 ]>
@@ -545,6 +546,7 @@ that is, GUI components such as <link linkend="GtkButton">GtkButton</link> or
     </partintro>
 
     &gtk-migrating-GtkFileChooser;
+    &gtk-migrating-GtkAction;
   </part>
 
   <part>
diff --git a/docs/reference/gtk/migrating-GtkAction.sgml b/docs/reference/gtk/migrating-GtkAction.sgml
new file mode 100644 (file)
index 0000000..a0ed936
--- /dev/null
@@ -0,0 +1,388 @@
+<chapter id="gtk-migrating-GtkAction">
+  <chapterinfo>
+    <author>
+      <firstname>Federico</firstname>
+      <surname>Mena-Quintero</surname>
+      <affiliation>
+       <address>
+         <email>federico@ximian.com</email>
+       </address>
+      </affiliation>
+    </author>
+  </chapterinfo>
+
+  <title>Migrating from old menu and toolbar systems to GtkAction</title>
+
+  <para>
+    Prior to GTK+ 2.4, there were several APIs in use to create menus
+    and toolbars.  GTK+ itself included #GtkItemFactory, which was
+    historically used in the GIMP; libgnomeui provided the gnome-ui
+    set of macros; libbonoboui provided a complex mechanism to do menu
+    merging across embedded components.  GTK+ 2.4 includes a system
+    for creating menus and toolbars, with merging of items, based
+    around the #GtkAction mechanism.
+  </para>
+
+  <section id="actions-and-action-groups">
+    <title>Actions and Action Groups</title>
+
+    <para>
+      A #GtkAction represents an operation that the user can perform
+      from the menus and toolbars of an application.  It is similar to
+      "verbs" in other menu systems.  A #GtkAction has a name, which
+      is its identifier, and it can have several widgets that
+      represent it in the user interface.  For example, an action for
+      <symbol>EditCopy</symbol> can have a menu item as well as a
+      toolbar button associated to it.  If there is nothing selected
+      in the document, the application can simply de-sensitize the
+      <symbol>EditCopy</symbol> action; this will cause both the menu
+      item and the toolbar button to be de-sensitized automatically.
+      Similarly, whenever the user selects the menu item or the
+      toolbar button associated to the <symbol>EditCopy</symbol>
+      action, the corresponding #GtkAction object will emit an
+      "activate" signal.
+    </para>
+
+    <para>
+      #GtkActionGroup is simply a group of #GtkAction objects.  An
+      application may want to have several groups:  one for global
+      actions such as "new document", "about", and "exit"; then one
+      group for each open document with actions specific to the
+      document, such as "cut", "copy", "paste", and "print".
+    </para>
+
+    <para>
+      Normal actions are simply commands, such as
+      <symbol>FileSave</symbol> or <symbol>EditCopy</symbol>.  Toggle
+      actions can be active or inactive, such as
+      <symbol>FormatBold</symbol> or <symbol>ViewShowRulers</symbol>.
+      Radio actions define a set of items for which one and only one
+      can be active at a time, for example, {
+      <symbol>ViewHighQuality</symbol>,
+      <symbol>ViewNormalQuality</symbol>,
+      <symbol>ViewLowQuality</symbol> }.
+    </para>
+  </section>
+
+  <section id="ui-manager">
+    <title>User Interface Manager Object</title>
+
+    <para>
+      #GtkUIManager is an object that can construct menu and toolbar
+      widgets from an XML description.  These widgets are in turn
+      associated to corresponding actions and action groups.
+    </para>
+
+    <para>
+      #GtkUIManager supports merging of menus and toolbars for
+      applications that have multiple components, each with separate
+      sets of commands.  For example, a word processor that can embed
+      images may want to have toolbar buttons for Bold and Italic when
+      the cursor is on a text block, but Crop and Brightness/Contrast
+      buttons when the cursor is on an image.  These actions, which
+      change depending on the state of the application, can be merged
+      and de-merged from a #GtkUIManager as appropriate.
+    </para>
+  </section>
+
+  <section id="migrating-gnomeuiinfo">
+    <title>Migrating from GnomeUIInfo</title>
+
+    <para>
+      Prior to GTK+ 2.4, some applications used the GnomeUIInfo
+      mechanism from
+      <filename>&lt;libgnomeui/gnome-app-helper.h&gt;</filename> to
+      define their menus and toolbars.  With it, a program decleres an
+      array of <structname>GnomeUIInfo</structname> structures, which
+      contain information for menu or toolbar items such as their
+      label, icon, and accelerator key.  Then, one calls
+      <function>gnome_app_fill_menu()</function> or
+      <function>gnome_app_fill_toolbar()</function>, or one of the
+      related functions, to create the appropriate widgets based on
+      these structures.
+    </para>
+
+    <para>
+      A downside of this API is that the same structures are used to
+      pass back pointers to the widgets that got created.  This means
+      that the structures cannot simply be kept around if the program
+      requires multiple instances of the user interface (e.g. several
+      windows); each new invocation of
+      <function>gnome_app_fill_menu()</function> would overwrite the
+      widget fields of the structures.
+    </para>
+
+    <para>
+      Another disadvantage is that there is no automatic way to
+      synchronize the state of related controls.  If there are toolbar
+      toogle buttons for "Bold", "Italic", "Underline", and also
+      corresponding menu items under "Format/Bold", etc., one has to
+      synchronize their toggled states by hand whenever the user
+      selects any one of them.
+    </para>
+
+    <para>
+      Finally, there is no way to do menu and toolbar merging for
+      applications that require embedded components.
+    </para>
+
+    <para>
+      To convert an application that uses GnomeUIInfo into the new
+      GtkAction mechanism, you need to do several things:
+    </para>
+
+    <orderedlist>
+      <listitem>
+       <para>
+         Separate your existing GnomeUIInfo entries into normal
+         actions, toggle actions, and radio actions, and then create a
+         separate array of #GtkActionEntry structures for each
+         group.  This will allow you to create the necessary
+         #GtkActionGroup objects.  Note that this does not describe
+         the actual "shape" that your menus and toolbars will have;
+         it simply defines the set of commands that will appear in them.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Create an XML description of your menus and toolbars for use
+         with #GtkUIManager.  This defines the actual shape of the
+         menus and toolbars.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Port the code that uses gnome-app and gnome-app-helper to
+         #GtkAction and #GtkUIManager.
+       </para>
+      </listitem>
+    </orderedlist>
+
+    <example id="gnomeuiinfo-example">
+      <title>GnomeUIInfo Example</title>
+
+      <para>
+       The following code shows a declaration of a simple menu bar to
+       be used with <function>gnome_app_fill_menu()</function> or
+       similar.  The menu hierarchy looks like this:
+      </para>
+
+      <itemizedlist>
+       <listitem>
+         <para><guimenu>File</guimenu></para>
+         <simplelist>
+           <member><guimenuitem>Open</guimenuitem></member>
+           <member><guimenuitem>&mdash;</guimenuitem></member>
+           <member><guimenuitem>Exit</guimenuitem></member>
+         </simplelist>
+       </listitem>
+
+       <listitem>
+         <para><guimenu>View</guimenu></para>
+         <simplelist>
+           <member><guimenuitem>Zoom In</guimenuitem></member>
+           <member><guimenuitem>Zoom Out</guimenuitem></member>
+           <member><guimenuitem>&mdash;</guimenuitem></member>
+           <member><guimenuitem>[ ] Full Screen</guimenuitem></member>
+           <member><guimenuitem>&mdash;</guimenuitem></member>
+           <member><guimenuitem>( ) High Quality</guimenuitem></member>
+           <member><guimenuitem>( ) Normal Quality</guimenuitem></member>
+           <member><guimenuitem>( ) Low Quality</guimenuitem></member>
+         </simplelist>
+       </listitem>
+      </itemizedlist>
+
+      <programlisting>
+static GnomeUIInfo file_menu_items[] = {
+  { GNOME_APP_UI_ITEM, "_Open", "Open a file",
+    open_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_OPEN,
+    'o', GDK_CONTROL_MASK, NULL },
+  { GNOME_APP_UI_SEPARATOR },
+  { GNOME_APP_UI_ITEM, "E_xit", "Exit the program",
+    exit_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_QUIT,
+    'q', GDK_CONTROL_MASK, NULL},
+  { GNOME_APP_UI_ENDOFINFO }
+};
+
+static GnomeUIInfo view_radio_items[] = {
+  { GNOME_APP_UI_ITEM, "_High Quality", "Display images in high quality, slow mode",
+    high_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL,
+    0, 0, NULL },
+  { GNOME_APP_UI_ITEM, "_Normal Quality", "Display images in normal quality",
+    normal_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL,
+    0, 0, NULL },
+  { GNOME_APP_UI_ITEM, "_Low Quality", "Display images in low quality, fast mode",
+    low_quality_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL,
+    0, 0, NULL },
+  { GNOME_APP_UI_ENDOFINFO }
+};
+
+static GnomeUIInfo view_menu_items[] = {
+  { GNOME_APP_UI_ITEM, "Zoom _In", "Zoom into the image",
+    zoom_in_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_ZOOM_IN,
+    GDK_PLUS, 0, NULL },
+  { GNOME_APP_UI_ITEM, "Zoom _Out", "Zoom away from the image",
+    zoom_out_callback, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GTK_STOCK_ZOOM_OUT,
+    GDK_MINUS, 0, NULL },
+  { GNOME_APP_UI_SEPARATOR },
+  { GNOME_APP_UI_TOGGLEITEM, "_Full Screen", "Switch between full screen and windowed mode",
+    full_screen_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL,
+    GDK_F11, 0, NULL },
+  { GNOME_APP_UI_SEPARATOR },
+  { GNOME_APP_UI_RADIOITEMS, NULL, NULL, view_radio_items },
+  { GNOME_APP_UI_ENDOFINFO }
+};
+
+static GnomeUIInfo menubar[] = {
+  { GNOME_APP_UI_SUBTREE, "_File", NULL, file_menu_items },
+  { GNOME_APP_UI_SUBTREE, "_View", NULL, view_menu_items },
+  { GNOME_APP_UI_ENDOFINFO }
+}
+      </programlisting>
+    </example>
+
+    <example id="gnomeuiinfo-action-entries">
+      <title><structname>GtkActionEntry</structname> Structures</title>
+
+      <para>
+       The following code is the set of actions that are present in
+       the <link linkend="gnomeuiinfo-example">previous
+       example</link>.  Note that the toggle and radio entries are
+       separate from normal actions.  Also, note that #GtkActionEntry
+       structures take key names in the format of
+       gdk_accelerator_parse() rather than key values plus modifiers;
+       you will have to convert these values by hand.  For example,
+       <constant>GDK_F11</constant> with no modifiers is equivalent
+       to a key name of <literal>"F11"</literal>.  Likewise,
+       <literal>"o"</literal> with
+       <constant>GDK_CONTROL_MASK</constant> is equivalent to
+       <literal>"&lt;ontrol&gt;O"</literal>.
+      </para>
+
+      <programlisting>
+/* Normal items */
+static GtkActionEntry entries[] = {
+  { "FileMenu", NULL, "_File" },
+  { "ViewMenu", NULL, "_View" },
+  { "Open", GTK_STOCK_OPEN, "_Open", "&lt;control&gt;O", "Open a file", open_action_callback },
+  { "Exit", GTK_STOCK_OPEN, "E_xit", "&lt;control&gt;Q", "Exit the program", exit_action_callback },
+  { "ZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "plus", "Zoom into the image", zoom_in_action_callback },
+  { "ZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "minus", "Zoom away from the image", zoom_out_action_callback },
+};
+
+/* Toggle items */
+static GtkToggleActionEntry toggle_entries[] = {
+  { "FullScreen", NULL, "_Full Screen", "F11", "Switch between full screen and windowed mode", full_screen_action_callback, FALSE }
+};
+
+/* Radio items */
+static GtkRadioActionEntry radio_entries[] = {
+  { "HighQuality", NULL, "_High Quality", NULL, "Display images in high quality, slow mode", 0 },
+  { "NormalQuality", NULL, "_Normal Quality", NULL, "Display images in normal quality", 1 },
+  { "LowQuality", NULL, "_Low Quality", NULL, "Display images in low quality, fast mode", 2 }
+};
+      </programlisting>
+    </example>
+
+    <example id="gnomeuiinfo-xml">
+      <title>XML Description</title>
+
+      <para>
+       After extracting the actions, you will need to create an XML
+       description of the actual layout of your menus and toolbars
+       for use with #GtkUIManager.  The following code shows a simple
+       menu bar that corresponds to the <link
+       linkend="gnomeuiinfo-example">previous example</link>.  Note
+       that the <guimenu>File</guimenu> and <guimenu>View</guimenu>
+       menus have their names specified in the <link
+       linkend="gnomeuiinfo-action-entries">action entries</link>,
+       not in the XML itself.  This is because the XML description
+       only contains <emphasis>identifiers</emphasis> for the items
+       in the GUI, rather than human-readable names.
+      </para>
+
+      <programlisting>
+static const char *ui_description =
+"&lt;ui&gt;"
+"  &lt;menubar name="MainMenu"&gt;"
+"    &lt;menu action="FileMenu"&gt;"
+"      &lt;menuitem action="Open"/&gt;"
+"      &lt;menuitem action="Exit"/&gt;"
+"    &lt;/menu&gt;"
+"    &lt;menu action="ViewMenu"&gt;"
+"      &lt;menuitem action="ZoomIn"/&gt;"
+"      &lt;menuitem action="ZoomOut"/&gt;"
+"      &lt;separator/&gt;"
+"      &lt;menuitem action="FullScreen"/&gt;"
+"      &lt;separator/&gt;"
+"      &lt;menuitem action="HighQuality"/&gt;"
+"      &lt;menuitem action="NormalQuality"/&gt;"
+"      &lt;menuitem action="LowQuality"/&gt;"
+"    &lt;/menu&gt;"
+"  &lt;/menubar&gt;"
+"&lt;/ui&gt;";
+      </programlisting>
+    </example>
+
+    <example id="gnomeuiinfo-code">
+      <title>Creating the Menu Bar</title>
+
+      <para>
+       In this last example, we will create a #GtkActionGroup based
+       on the <link linkend="gnomeuiinfo-action-entries">action
+       entries</link> we created above.  We will then create a
+       #GtkUIManager with the <link linkend="gnomeuiinfo-xml">XML
+       description</link> of the menu layout.  We will also extract
+       the accelerator group and the widgets from the #GtkUIManager
+       put them into a window.
+      </para>
+
+      <programlisting>
+GtkWidget *window;
+GtkWidget *vbox;
+GtkWidget *menubar;
+GtkActionGroup *action_group;
+GtkUIManager *ui_manager;
+GtkAccelGroup *accel_group;
+GError *error;
+
+window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+vbox = gtk_vbox_new (FALSE, 0);
+gtk_container_add (GTK_CONTAINER (window), vbox);
+
+action_group = gtk_action_group_new ("MenuActions");
+gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window);
+gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window);
+gtk_action_group_add_radio_actions (action_group, radio_entries, G_N_ELEMENTS (radio_entries), 0, radio_action_callback, window);
+
+ui_manager = gtk_ui_manager_new ();
+gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+
+accel_group = gtk_ui_manager_get_accel_group (ui_manager);
+gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+error = NULL;
+if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &amp;error))
+  {
+    g_message ("building menus failed: %s", error-&gt;message);
+    g_error_free (error);
+    exit (EXIT_FAILURE);
+  }
+
+menubar = gtk_ui_manager_get_widget ("/MainMenu");
+gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
+
+gtk_widget_show_all (window);
+      </programlisting>
+    </example>
+  </section>
+
+</chapter>
+
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
+End:
+-->